package com.puhui.lib.utils;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Build;
import androidx.core.content.ContextCompat;
import android.util.Base64;
import android.widget.TextView;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * Copyright: 人人普惠
 * Created by TangJian on 2017/4/20.
 * Description:  ????bmp.recycle()  是否需要调用该方法释放
 * Modified By:
 */

@SuppressWarnings("unused")
public class BitmapUtils {

    /***
     * 复制一份新的Bitmap
     */
    public static Bitmap toRoundCorner(Bitmap bitmap) {
        return toRoundCorner(bitmap, 0);
    }

    /***
     * 复制一份新的Bitmap
     */
    public static Bitmap toRoundCorner(Bitmap bitmap, int roundPx) {
        Bitmap roundCornerBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.RGB_565);
        Canvas canvas = new Canvas(roundCornerBitmap);
        int color = 0xff424242;// int color = 0xff424242;
        Paint paint = new Paint();
        paint.setColor(color);
        // 防止锯齿
        paint.setAntiAlias(true);
        Rect rect = new Rect(0, 0, roundCornerBitmap.getWidth(), roundCornerBitmap.getHeight());
        RectF rectF = new RectF(rect);
        // 相当于清屏
        canvas.drawRGB(0, 0, 0);
        // 先画了一个带圆角的矩形
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        // 再把原来的bitmap画到现在的bitmap！！！注意这个理解
        canvas.drawBitmap(bitmap, rect, rect, paint);
        return roundCornerBitmap;
    }

    /***
     * 图片转Base4
     */
    public static String bitmapToBase64(Bitmap bitmap) {
        String result = null;
        ByteArrayOutputStream baos = null;
        try {
            if (bitmap != null) {
                baos = new ByteArrayOutputStream();
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);

                baos.flush();
                baos.close();

                byte[] bitmapBytes = baos.toByteArray();
                result = Base64.encodeToString(bitmapBytes, Base64.DEFAULT);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (baos != null) {
                    baos.flush();
                    baos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * base64转为bitmap
     */
    public static Bitmap base64ToBitmap(String base64Data) {
        try {
            byte[] bytes = Base64.decode(base64Data, Base64.DEFAULT);
            return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /***
     * 1. 质量压缩
     * 设置bitmap options属性，降低图片的质量，像素不会减少
     * 第一个参数为需要压缩的bitmap图片对象，第二个参数为压缩后图片保存的位置
     * 设置options 属性0-100，来实现压缩
     */
    public static void compressImageToFile(Bitmap bmp, File file) {
        // 0-100 100为不压缩
        int options = 100;
        int maxSize = 500;  //500kb
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);
        // 把压缩后的数据存放到baos中
        while (baos.toByteArray().length / 1024 > maxSize) {
            baos.reset();
            options -= 5;
            if (options <= 40) {
                //最大压缩到40，压缩的太过分的话，图片会严重失真(丢帧)
                break;
            }
            bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);
        }

        try {
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(baos.toByteArray());
            fos.flush();
            fos.close();
            baos.close();
            bmp.recycle();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /***
     * 2. 尺寸压缩
     * 通过缩放图片像素来减少图片占用内存大小
     */
    public static void compressBitmapToFile(Bitmap bmp, File file) {
        // 尺寸压缩倍数,值越大，图片尺寸越小
        float ratio = 1f;
        int size = bmp.getByteCount();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            size = bmp.getAllocationByteCount();
        }
        if (size > 1024 * 1024) {
            ratio = (float) Math.sqrt(size / 1024 / 1024f);
        }

        Bitmap result = Bitmap.createBitmap((int) (bmp.getWidth() / ratio), (int) (bmp.getHeight() / ratio), Bitmap.Config.RGB_565);
        Canvas canvas = new Canvas(result);
        Rect rect = new Rect(0, 0, (int) (bmp.getWidth() / ratio), (int) (bmp.getHeight() / ratio));
        canvas.drawBitmap(bmp, null, rect, null);
        bmp.recycle();   //????要不要加呢

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // 把压缩后的数据存放到baos中
        result.compress(Bitmap.CompressFormat.PNG, 100, baos);
//        result.compress(Bitmap.CompressFormat.JPEG, 100, baos);//30 是压缩率，表示压缩70%; 如果不压缩是100，表示压缩率为0
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(file);
            fos.write(baos.toByteArray());
            fos.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            result.recycle();
            if (null != fos) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /***
     * 2. 尺寸压缩  按照宽高比压缩  压缩图片到指定的宽高
     * 通过缩放图片像素来减少图片占用内存大小
     */
    public static Bitmap compressBitmap(Bitmap bmp, int width, int height) {
        // 尺寸压缩倍数,值越大，图片尺寸越小
        float ratio = 1f;
        int size = bmp.getByteCount();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            size = bmp.getAllocationByteCount();
        }

        int compressSize = width * height * getPixelsCount(bmp.getConfig());
        if (size > compressSize) {
            ratio = (float) Math.sqrt(size / (float) compressSize);
        }
        // 压缩Bitmap到对应尺寸
        width = (int) (bmp.getWidth() / ratio);
        height = (int) (bmp.getHeight() / ratio);
        Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        Canvas canvas = new Canvas(result);
        Rect rect = new Rect(0, 0, width, height);
        canvas.drawBitmap(bmp, null, rect, null);
        bmp.recycle();   //????要不要加呢
        return result;
    }

    /**
     * Bitmap.Config ARGB_4444：每个像素占四位，即A=4，R=4，G=4，B=4，那么一个像素点占4+4+4+4=16位 
     * Bitmap.Config ARGB_8888：每个像素占四位，即A=8，R=8，G=8，B=8，那么一个像素点占8+8+8+8=32位
     * Bitmap.Config RGB_565：每个像素占四位，即R=5，G=6，B=5，没有透明度，那么一个像素点占5+6+5=16位
     * Bitmap.Config ALPHA_8：每个像素占四位，只有透明度，没有颜色。
     */
    private static int getPixelsCount(Bitmap.Config config) {
        if (config == Bitmap.Config.ARGB_8888) {
            return 4;
        } else if (config == Bitmap.Config.RGB_565) {
            return 2;
        } else if (config == Bitmap.Config.ARGB_4444) {
            return 2;
        } else if (config == Bitmap.Config.ALPHA_8) {
            return 1;
        } else {
            return 2;
        }
    }

    /***
     * 2. 尺寸压缩 压缩到图片大小只有1M
     * 通过缩放图片像素来减少图片占用内存大小
     */
    public static Bitmap compressBitmap(Bitmap bmp) {
        // 尺寸压缩倍数,值越大，图片尺寸越小
        float ratio = 1f;
        int size = bmp.getByteCount();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            size = bmp.getAllocationByteCount();
        }
        if (size > 1024 * 1024) {
            ratio = (float) Math.sqrt(size / 1024 / 1024);
        }
        // 压缩Bitmap到对应尺寸
        int width = (int) (bmp.getWidth() / ratio);
        int height = (int) (bmp.getHeight() / ratio);
        Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        Canvas canvas = new Canvas(result);
        Rect rect = new Rect(0, 0, width, height);
        canvas.drawBitmap(bmp, null, rect, null);
        return result;
    }

    public static Bitmap compressBitmap(Context context, int resourceId, int width, int height) {
        return compressBitmap(context, resourceId, width, height, null);
    }

    /**
     * 根据资源id获取图片，并根据给定的宽高压缩图片，且复用图片内存空间
     *
     * @param context        上下文
     * @param resourceId     图片资源id
     * @param width          所需要的宽
     * @param height         所需高
     * @param reusableBitmap 复用的bitmap内存空间
     * @return 返回压缩后的bitmap
     * //
     */
    public static Bitmap compressBitmap(Context context, int resourceId, int width, int height, Bitmap reusableBitmap) {
        Bitmap bitmap = null;
        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;  //设置只解码出outxxx参数，比如宽高等
            Resources resources = context.getApplicationContext().getResources();
            BitmapFactory.decodeResource(resources, resourceId, options);
            //根据宽高进行缩放
            int w = options.outWidth;
            int h = options.outHeight;
            //计算缩放系数
            int inSampleSize = 1;
            //多除以一次2，保证最后得到的宽高都是大于所需要的宽高的
            while (w / inSampleSize / 2 > width && h / inSampleSize / 2 > height) {
                inSampleSize *= 2;
            }

            //这样的算法压缩的话更接近指定的尺寸
//            int scaleW = w / width;
//            int scaleH = h / height;
//            inSampleSize = scaleW < scaleH ? scaleW : scaleH;

            options.inSampleSize = inSampleSize;

            options.inPreferredConfig = Bitmap.Config.RGB_565;  //设置为RGB_565格式，去掉Alpha
            if (null != reusableBitmap) {
                options.inMutable = true; //设置为可复用
                options.inBitmap = reusableBitmap;
            }
            options.inScaled = false;  //禁止缩放，防止因为图片位置放错了导致内存成倍增加
            options.inJustDecodeBounds = false;  //解码出真实的bitmap
            bitmap = BitmapFactory.decodeResource(resources, resourceId, options);
        } catch (Exception e) {
            //这段代码时不会产生异常的，但是如果resourceId的值出问题的话，就会抛出异常了。这里主要是为了捕获该异常
            e.printStackTrace();
        }
        return bitmap;
    }

    /***
     * 设置图片的采样率，降低图片像素
     */
    public static void compressBitmap(String filePath, File file) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        //采样率  数值越高，图片像素越低
        options.inSampleSize = 2;
        Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // 把压缩后的数据存放到baos中
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(baos.toByteArray());
            fos.flush();
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 得到bitmap的大小
     */
    public static int getBitmapSize(Bitmap bitmap) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {    //API 19
            return bitmap.getAllocationByteCount();
        }
//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {//API 12
//            return bitmap.getByteCount();
//        }
//        // 在低版本中用一行的字节x高度
//        return bitmap.getRowBytes() * bitmap.getHeight();  //earlier version
        return bitmap.getByteCount();
    }

    /**
     * 从服务器取图片, 转换成Bitmap
     */
    public static Bitmap returnBitMap(String url) {
        Bitmap bitmap = null;
        try {
            URL myFileUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection();
            conn.setDoInput(true);
            conn.connect();
            InputStream is = conn.getInputStream();
            bitmap = BitmapFactory.decodeStream(is);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bitmap;
    }

    /**
     * set TextView DrawableLeft or DrawableRight
     *
     * @param leftOrRight true   left; false   right
     */
    public static void setTextViewDrawable(Context context, int resourceId, TextView textView, boolean leftOrRight) {
        try {
            Drawable drawable = ContextCompat.getDrawable(context, resourceId);
            if (null != drawable) {
                drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());
                if (leftOrRight) {
                    textView.setCompoundDrawables(drawable, null, null, null);
                } else {
                    textView.setCompoundDrawables(null, null, drawable, null);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
